package com.frank.oj.core.judge;

import com.frank.model.dto.TestJudgeReq;
import com.frank.model.dto.TestJudgeRes;
import com.frank.model.entity.judge.Judge;
import com.frank.model.entity.problem.Problem;
import com.frank.model.entity.user.UserAcproblem;
import com.frank.oj.common.Constants;
import com.frank.oj.core.judge.entity.LanguageConfig;
import com.frank.oj.dao.ContestRecordEntityService;
import com.frank.oj.dao.UserAcproblemEntityService;
import com.frank.oj.exception.SystemError;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.HashMap;

/**
 * @author frank
 * @Date 2024/4/27
 */
@Component
public class JudgeContext {

    @Resource
    private JudgeStrategy judgeStrategy;
    @Resource
    private UserAcproblemEntityService userAcproblemEntityService;

    @Resource
    private ContestRecordEntityService contestRecordEntityService;

    @Resource
    private LanguageConfigLoader languageConfigLoader;

    public TestJudgeRes testJudge(TestJudgeReq testJudgeReq) {
        LanguageConfig languageConfig= languageConfigLoader.getLanguageConfigByName(testJudgeReq.getLanguage());

        // c和c++为一倍时间和空间，其它语言为2倍时间和空间
        if (languageConfig.getSrcName()==null||(!languageConfig.getSrcName().endsWith(".c")&&!languageConfig.getSrcName().endsWith(".cpp"))){
            testJudgeReq.setTimeLimit(testJudgeReq.getTimeLimit()*2);
            testJudgeReq.setMemoryLimit(testJudgeReq.getMemoryLimit()*2);
        }

        return judgeStrategy.testJudge(testJudgeReq);
    }

    public void updateOtherTable(Long submitId, Integer status, Long cid, String uid, Long pid, Long gid, Integer score, Integer useTime) {
        if (cid==0){// 非比赛提交
            if (status.intValue()== Constants.Judge.STATUS_ACCEPTED.getStatus()&&gid==null){
                userAcproblemEntityService.saveOrUpdate(new UserAcproblem().setPid(pid).setUid(uid).setSubmitId(submitId));
            }
        }else {
            contestRecordEntityService.updateContestRecord(score,status,submitId,useTime);
        }
    }

    public Judge judge(Problem problem, Judge judge) {
        LanguageConfig languageConfig = languageConfigLoader.getLanguageConfigByName(judge.getLanguage());
        if (languageConfig.getSrcName()==null||(!languageConfig.getSrcName().endsWith(".c")&&!languageConfig.getSrcName().endsWith(".cpp"))){
            problem.setTimeLimit(problem.getTimeLimit()*2);
            problem.setMemoryLimit(problem.getMemoryLimit()*2);
        }
        HashMap<String, Object> judgeResult = judgeStrategy.judge(problem, judge);

        Judge finalJudgeRes = new Judge();
        finalJudgeRes.setSubmitId(judge.getSubmitId());
        // 如果是编译失败、提交错误或者系统错误就有错误提醒
        if (judgeResult.get("code") == Constants.Judge.STATUS_COMPILE_ERROR.getStatus() ||
                judgeResult.get("code") == Constants.Judge.STATUS_SYSTEM_ERROR.getStatus() ||
                judgeResult.get("code") == Constants.Judge.STATUS_RUNTIME_ERROR.getStatus() ||
                judgeResult.get("code") == Constants.Judge.STATUS_SUBMITTED_FAILED.getStatus()) {
            finalJudgeRes.setErrorMessage((String) judgeResult.getOrDefault("errMsg", ""));
        }
        // 设置最终结果状态码
        finalJudgeRes.setStatus((Integer) judgeResult.get("code"));
        // 设置最大时间和最大空间不超过题目限制时间和空间
        // kb
        Integer memory = (Integer) judgeResult.get("memory");
        finalJudgeRes.setMemory(Math.min(memory, problem.getMemoryLimit() * 1024));
        // ms
        Integer time = (Integer) judgeResult.get("time");
        finalJudgeRes.setTime(Math.min(time, problem.getTimeLimit()));
        // score
        finalJudgeRes.setScore((Integer) judgeResult.getOrDefault("score", null));
        // oi_rank_score
        finalJudgeRes.setOiRankScore((Integer) judgeResult.getOrDefault("oiRankScore", null));

        return finalJudgeRes;
    }

    public Boolean compileSpj(String code, Long pid, String language, HashMap<String, String> extraFiles) throws SystemError {
        return Compiler.compileSpj(code,pid,language,extraFiles);
    }

    public Boolean compileInteractive(String code, Long pid, String language, HashMap<String, String> extraFiles) throws SystemError {
        return Compiler.compileInteractive(code,pid,language,extraFiles);
    }
}
